#include "StdAfx.h"
#include "AGAttachmentControl.h"
#include "AnimationGraphCVars.h"
#include "AnimationGraphState.h"

CAGAttachmentControl::CAGAttachmentControl( CAGAttachmentControlFactory * pFactory ) 
//: IAnimationStateNode(eASNF_Update),
: m_pFactory(pFactory)
{  
}

void CAGAttachmentControl::EnteredState( SAnimationStateData& data )
{
	ICharacterInstance *pCharacter = data.pEntity->GetCharacter(0);

	if (!pCharacter || 0 == m_pFactory->GetAttachmentName()[0])
		return;
	
	// get attachment, return if it doesn't exist
	IAttachmentManager* pIAttachmentManager = pCharacter->GetIAttachmentManager();
	IAttachment* pA = pIAttachmentManager->GetInterfaceByName(m_pFactory->GetAttachmentName());  

	bool doLog = CAnimationGraphCVars::Get().m_log > 0;

	if (!pA)
	{
		if (doLog)
			CryLog("Attachment Control Modifier: Attachment %s not found (%s), returning..", m_pFactory->GetAttachmentName().c_str(), data.pEntity->GetName());
		return;
	}

	if (m_pFactory->m_controlType == CAGAttachmentControlFactory::ePlayAnimation)
	{
		StartAttachmentAnimation(pA, doLog);
	}

	if (m_pFactory->m_controlType == CAGAttachmentControlFactory::eStopAnimation)
	{
		StopAttachmentAnimation(pA, doLog);
	}

	if (m_pFactory->m_controlType == CAGAttachmentControlFactory::eShowAttachment)
	{
		// Unhide the attachment
		pA->HideAttachment(false);
	}

	if (m_pFactory->m_controlType == CAGAttachmentControlFactory::eHideAttachment)
	{
		// Hide the attachment
		pA->HideAttachment(true);
	}
}

void CAGAttachmentControl::EnterState( SAnimationStateData& data, bool dueToRollback )
{
}

bool CAGAttachmentControl::CanLeaveState( SAnimationStateData& data )
{
	return true;
}

void CAGAttachmentControl::LeftState( SAnimationStateData& data, bool wasEntered )
{
	if (wasEntered)
	{
		ICharacterInstance *pCharacter = data.pEntity->GetCharacter(0);
		if (pCharacter)
		{
			// At some point in the future, if the modifier's functionality is expanded, this would
			// the place to stop an animation, show or hide an attachment
		}
	}

	delete this;
}

void CAGAttachmentControl::LeaveState( SAnimationStateData& data )
{
}

void CAGAttachmentControl::GetCompletionTimes( SAnimationStateData& data, CTimeValue start, CTimeValue& hard, CTimeValue& sticky )
{  
}

void CAGAttachmentControl::Update( SAnimationStateData& data )
{	  
}

const IAnimationStateNodeFactory::Params * CAGAttachmentControlFactory::GetParameters()
{
	static const Params params[] = 
	{
		{true,  "string", "attachment",		"Attachment Name",			"" },
		{true,  "int",		"controlType",	"Control Type",					"0" },

		{true,  "string", "animName",			"Animation Name",				"" },
    {true,  "bool",		"looping",			"Loop Animation",				"false" },
		{true,  "int",		"layer",				"Animation Layer",      "0" },

		{true,  "int",		"stoplayer",		"Stop Animation Layer", "0" },
		{true,  "float",  "stoptime",			"Blendout Time",				"0.4" },
		{0}
	};
	return params;
}

bool CAGAttachmentControlFactory::Init( const XmlNodeRef& node, IAnimationGraphPtr )
{
	// <AttachmentControl attachment="XXX" control="YYY">
	// one of these children:
	//			<PlayAnimation animName="XXX" looping="XXX" layer="XXX" />
	//			<StopAnimation layer="XXX" blendTime="XXX" />
	// </AttachmentControl/>

	bool ok = true;
	
	m_attachment = node->getAttr("attachment");
	node->getAttr("control", m_controlType);

	if (m_controlType == ePlayAnimation)
	{
		const XmlNodeRef animNode = node->findChild("PlayAnimation");
		m_animationName = animNode->getAttr("animName");
		animNode->getAttr("looping", m_animationLoop);
		animNode->getAttr("layer", m_animationLayer);
	}
	if (m_controlType == eStopAnimation) 
	{
		const XmlNodeRef stopAnimNode = node->findChild("StopAnimation");
		stopAnimNode->getAttr("layer", m_stopAnimLayer);
		stopAnimNode->getAttr("blendTime", m_stopAnimTime);
	}
  
	return true;
}


void CAGAttachmentControlFactory::Release()
{
	delete this;
}

IAnimationStateNode * CAGAttachmentControlFactory::Create()
{
	return new CAGAttachmentControl(this);
}

const char * CAGAttachmentControlFactory::GetCategory()
{
	return "AttachmentControl";
}

const char * CAGAttachmentControlFactory::GetName()
{
	return "AttachmentControl";
}

void CAGAttachmentControlFactory::SerializeAsFile(bool reading, AG_FILE *file)
{
	FileSerializationHelper h(reading, file);

	h.StringValue(&m_attachment);
	h.Value(&m_controlType);

	if (m_controlType == ePlayAnimation)
	{
		h.StringValue(&m_animationName);
		h.Value(&m_animationLoop);
		h.Value(&m_animationLayer);
	}

	if (m_controlType == eStopAnimation)
	{
		h.Value(&m_stopAnimLayer);
		h.Value(&m_stopAnimTime);
	}
}


void CAGAttachmentControl::StartAttachmentAnimation( IAttachment* pA, bool doLog )
{
	if (0 == m_pFactory->GetAnimationName()[0])
		return;

	// Get animation id
	if (pA->GetIAttachmentObject() == NULL)
	{
		if (doLog)
			CryLog("Attachment Control Modifier: Attachment %s has no object. Quitting.", m_pFactory->GetAttachmentName().c_str());
		return;
	}

/*
	if (pA->GetIAttachmentObject()->GetICharacterInstance() == NULL)
	{
		if (doLog)
			CryLog("Attachment Control Modifier: Attachment %s has no character instance. Quitting.", m_pFactory->GetAttachmentName().c_str());
		return;
	}

	int animId = pA->GetIAttachmentObject()->GetICharacterInstance()->GetIAnimationSet()->GetAnimIDByName(m_pFactory->GetAnimationName().c_str());
	if (animId < 0)
	{
		if (doLog)
			CryLog("Attachment Control Modifier: Attachment %s has no animation of name %s. Quitting.", m_pFactory->GetAttachmentName().c_str(), m_pFactory->GetAnimationName().c_str());
		return;
	}
*/

	// Start animation with parameters
	CryCharAnimationParams params;
	params.m_nFlags |= m_pFactory->GetLoopingAnim() ? CA_LOOP_ANIMATION : CA_REPEAT_LAST_KEY;
	params.m_nLayerID = m_pFactory->GetLayerNumber();
//	pA->GetIAttachmentObject()->GetICharacterInstance()->GetISkeletonAnim()->StartAnimationById(animId, params);
	pA->GetIAttachmentObject()->StartAnimation(m_pFactory->GetAnimationName(), params);
}

void CAGAttachmentControl::StopAttachmentAnimation( IAttachment* pA, bool doLog )
{
	// Get animation id
	if (pA->GetIAttachmentObject() == NULL)
	{
		if (doLog)
			CryLog("Attachment Control Modifier: Attachment %s has no object. Quitting.", m_pFactory->GetAttachmentName().c_str());
		return;
	}

	if (pA->GetIAttachmentObject()->GetICharacterInstance() != NULL)
	{
		pA->GetIAttachmentObject()->GetICharacterInstance()->GetISkeletonAnim()->StopAnimationInLayer(m_pFactory->m_stopAnimLayer, m_pFactory->m_stopAnimTime);
	}
	else
	{
		pA->GetIAttachmentObject()->StopAnimationInLayer(m_pFactory->m_stopAnimLayer);
	}
}
